package com.linrung.sf.scheduler.zwwx.jms;

import com.linrung.core.cache.ICacheClient;
import com.linrung.core.model.ResultData;
import com.linrung.core.utils.JsonUtils;
import com.linrung.gds.auth.GdsAuthUtils;
import com.linrung.gds.auth.YzyConfig;
import com.linrung.gds.auth.dto.YzyMsgResponseDto;
import com.linrung.gdsfrz.RequestApiUtils;
import com.linrung.gdsfrz.Signature;
import com.linrung.sf.scheduler.zwwx.entity.ReportEntity;
import com.linrung.sf.scheduler.zwwx.entity.ZwwxMsgType;
import com.linrung.sf.scheduler.zwwx.ZwwxMsgSyncService;
import com.linrung.sf.scheduler.zwwx.entity.AccessEntity;
import com.linrung.platform.job.jobConfig.JobConfigEntity;
import com.linrung.sf.scheduler.zwwx.service.ZwwxMessageSendService;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author Administrator
 *
 */
@Service("zwwxMsgConsumerService")
public class ZWWXMsgConsumerService implements MessageListener{

	private static Logger logger = Logger.getLogger(ZWWXMsgConsumerService.class);

	private static String TRY_SEND_COUNT_CACHE_KE = "ZWWX_TRY_SEND:";

	@Autowired
	private ZwwxMessageSendService messageService;

	@Autowired
	private ICacheClient cacheClient;

	//获取政务微信token的统一API地址
	private String zwwxTokenUnApiUrl = null;
	//获取政务微信token验证ID
	private Integer tokenValid = null;
	//获取政务微信发送URL
	private String sendUrl = null;

	private static boolean isError = false;
	private static boolean isSendError = false;
	private static String errorSmsContentFormat = "政务微信推送失败：errorCode = %s, errorMsg = %s， 请及时处理。";

	@Override
	public void onMessage(Message message) {
		try {
			String msgContent = message.getStringProperty(ZWWXMsgProductorService.MSG_CONTENT);
			String pfMsgReceiveId = message.getStringProperty(ZWWXMsgProductorService.PF_MESSAGE_RECEIVE_ID);
			String msgType = message.getStringProperty(ZWWXMsgProductorService.MSG_TYPE);
			messageBody(msgContent, pfMsgReceiveId, msgType);
		} catch (JMSException e) {
			logger.error("消费政务微信推送消息获取参数异常", e);
		}
	}

	/**
	 * 处理参数
	 * @param msgContent
	 * @param pfMsgReceiveId
	 * @param msgType
	 */
	public void messageBody(String msgContent, String pfMsgReceiveId, String msgType){
		boolean isReady = true;
		Integer agentid = null;
		logger.info(String.format("开始消费政务微信JMS============, pfMsgReceiveId = %s", pfMsgReceiveId));
		if(StringUtils.isBlank(pfMsgReceiveId)) {
			logger.error(String.format("消费政务微信推送获取jms平台消息接收表的ID参数=%s，为空了，直接丢弃。", ZWWXMsgProductorService.PF_MESSAGE_RECEIVE_ID));
			return ;
		}
		if(StringUtils.isBlank(msgContent)) {
			logger.error(String.format("消费政务微信推送消息获取jms消息内容参数=%s，为空了，直接丢弃。", ZWWXMsgProductorService.MSG_CONTENT));
			return ;
		}

		JobConfigEntity jobConfig = cacheClient.get(ZwwxMsgSyncService.ZWWX_JOB_PARAM_CACHE_KEY, JobConfigEntity.class);
		if(jobConfig == null) {
			logger.error("定时任务参数配置还没准备好，暂不推送");
			isReady = false;
		}
		String tokenUrl = null;
		if(jobConfig != null && isReady) {
			zwwxTokenUnApiUrl = jobConfig.getParams().get("REMOTE_URL");
			if(StringUtils.isBlank(zwwxTokenUnApiUrl)) {
				logger.error("请在定时任务参数配置中配置政务微信Token获取统一API地址【REMOTE_URL】参数，暂不推送");
				isReady = false;
			}

			String tokenValidStr = jobConfig.getParams().get("TOKENVALID");
			if(StringUtils.isBlank(tokenValidStr)) {
				logger.error("请在定时任务参数配置中配置消息来源子编码映射【TOKENVALID】参数，暂不推送");
				isReady = false;
			}
			tokenValid = Integer.parseInt(tokenValidStr);
			sendUrl = jobConfig.getParams().get("SENDURL");
			if(StringUtils.isBlank(sendUrl)) {
				logger.error("请在定时任务参数配置中配置消息来源子编码映射【SENDURL】参数，暂不推送");
				isReady = false;
			}

			//参数验证
			String agentidParamName = "AGENTID";
			String agentidStr = jobConfig.getParams().get(agentidParamName);
			if(StringUtils.isBlank(agentidStr)) {
				logger.error(String.format("发送政务微信消息时，agentid参数【%S】没有配置，暂不推送，msgReceiverId = %s", agentidParamName, pfMsgReceiveId));
				isReady = false;
			}
			try {
				agentid = Integer.parseInt(agentidStr);
			} catch(Exception e) {
				logger.error(String.format("发送政务微信消息时，agentid参数【%S】不是整数，暂不推送，msgReceiverId = %s", agentidParamName, pfMsgReceiveId));
				isReady = false;
			}

		}

		if(isReady == false) {
			//参数没准备好，更新数据状态为待发送，下次再发送
			logger.error(String.format("推送政务微信消息时，参数没有配置全，更新政务微信消息发送状态为待发送，下次再发送，msgReceiverId = %s",  pfMsgReceiveId));
			if (Objects.equals(msgType, ZwwxMsgType.textCard.getValue())) {
				messageService.updateReceiverWxSendStateById(pfMsgReceiveId, "0");
			}else if (Objects.equals(msgType, ZwwxMsgType.text.getValue())) {
//				lrJmsMessageService.updateReceiverWxSendStateById(pfMsgReceiveId, 0);
			}else{
				//如果没有给msgType，则是默认的文本卡发送textCard
				messageService.updateReceiverWxSendStateById(pfMsgReceiveId, "0");
			}
		} else {
//			Integer state = null;
//			ResultData<YzyConfig> yzyConfigResultData = GdsAuthUtils.initYzyPropertiesConfig(null);
//			if(yzyConfigResultData.getSuccess()) {
//				state = onSendYzyMessageHandle(msgContent, pfMsgReceiveId);
//			} else {
			Integer state = onSendMessageHandle(agentid, msgContent, pfMsgReceiveId);
//			}
			if(state != null){
				if (Objects.equals(msgType, ZwwxMsgType.textCard.getValue())) {
					messageService.updateReceiverWxSendStateById(pfMsgReceiveId, String.valueOf(state));
				}else if (Objects.equals(msgType, ZwwxMsgType.text.getValue())) {
//					lrJmsMessageService.updateReceiverWxSendStateById(pfMsgReceiveId, state);
				}else{
					messageService.updateReceiverWxSendStateById(pfMsgReceiveId, String.valueOf(state));
				}
			}
		}
		logger.info(String.format("结束消费政务微信JMS============, pfMsgReceiveId = %s", pfMsgReceiveId));
	}

	/**
	 * 发送消息句柄
	 * @param agentid
	 * @param msgContent
	 * @param pfMsgReceiveId 可看作可识别有来源的唯一ID
	 * @return
	 */
	private Integer onSendMessageHandle(Integer agentid, String msgContent, String pfMsgReceiveId){
		int resultStatus = sendMessageToWx(agentid, msgContent);
		//发送失败需要更新状态，成功不处理
		if(resultStatus != ZwwxMsgSyncService.RESULT_STATUS_SUCCESS) {
			//失败重发
			boolean isRepeatSend = true;
			if(resultStatus == ZwwxMsgSyncService.RESULT_STATUS_API_SYS_BUSY) {
				String tryCacheKey = TRY_SEND_COUNT_CACHE_KE + pfMsgReceiveId;
				Integer trySendCount = cacheClient.getInteger(tryCacheKey);
				if(trySendCount == null) {
					trySendCount = 0;
				}
				trySendCount = trySendCount.intValue() + 1;
				cacheClient.set(tryCacheKey, trySendCount);

				if(trySendCount.intValue() >= 3) {
					//尝试发送3次后，就不发送了
					logger.error(String.format("推送政务微信消息时失败，政务微信系统繁忙，已经尝试发送了%d次，丢弃不再发送了，msgReceiverId = %s",  trySendCount, pfMsgReceiveId));
					cacheClient.delete(tryCacheKey);
					return 4;
				}
			}
			if(isRepeatSend) {
				logger.error(String.format("推送政务微信消息时失败，失败信息见上面信息，更新政务微信消息发送状态为待发送，下次再发送，msgReceiverId = %s",  pfMsgReceiveId));
				return 0;
			}
		}
		return null;
	}

	/**
	 * 调用政务微信接口发送政务微信
	 * @param agentid
	 * @param msg
	 * @return
	 */
	private int sendMessageToWx(int agentid, String msg){
		int resultStatus = ZwwxMsgSyncService.RESULT_STATUS_FAIL;
		try{
			AccessEntity accessEntity = getToken(agentid);
			if(accessEntity == null) {
				logger.error(String.format("推送微信消息时，获取不到Token, 原因见上面信息, %s", msg));
				return resultStatus;
			}
			String url = this.sendUrl;
			String sendUrl = String.format(url, accessEntity.getAccess_token());
			int timeOut = 1000 * 60 * 5;
			RequestConfig requestConfig = RequestConfig.custom()
					.setConnectTimeout(timeOut)//一、连接超时：connectionTimeout-->指的是连接一个url的连接等待时间
					.setSocketTimeout(timeOut)// 二、读取数据超时：SocketTimeout-->指的是连接上一个url，获取response的返回等待时间
					.setConnectionRequestTimeout(timeOut)
					.build();
			HttpClient client = HttpClients.createDefault();
			HttpPost post = new HttpPost(sendUrl);
			/**
			String paasId = RequestApiUtils.getPaasId(RequestApiUtils.API_TYPE_TYPT);
			String paasToken = RequestApiUtils.getPaasToken(RequestApiUtils.API_TYPE_TYPT);
			Signature sign = new Signature(paasId, paasToken);
			post.addHeader("x-tif-paasid", sign.getPaasId());
			post.addHeader("x-tif-timestamp", sign.getTimestamp());
			post.addHeader("x-tif-signature", sign.getSignature());
			post.addHeader("x-tif-nonce", sign.getNonce());
			**/
			StringEntity entity = new StringEntity(msg,"UTF-8");
			post.setEntity(entity);
			post.setConfig(requestConfig);

			HttpResponse response = client.execute(post);
			String errorSmsContent = null;
			int httpStatusCode = response.getStatusLine().getStatusCode();
			if ( httpStatusCode == 200) {
				HttpEntity resEntity = response.getEntity();
				String message = EntityUtils.toString(resEntity, "utf-8");
				ReportEntity report = JsonUtils.converObjectFromJson(message, ReportEntity.class);
				String errorCode = report.getErrcode();
				String errorMsg = report.getErrmsg();

				if(errorCode.equals("0")){
					resultStatus = ZwwxMsgSyncService.RESULT_STATUS_SUCCESS;
				} else if(errorCode.equals("-1")) {
//	            	logger.error(String.format("推送微信消息失败， errorCode=%s, errorMsg=%s", errorCode, errorMsg));
					logger.error(String.format("政务微信消息内容 = %s， sendUrl = %s， response = %s", msg, sendUrl, message));
					resultStatus = ZwwxMsgSyncService.RESULT_STATUS_API_SYS_BUSY;
					isError = true;
				} else if("42001".equals(errorCode)) {
					//token过期
					clearTokenInRedis(agentid);
				}else {
//	            	logger.error(String.format("推送微信消息失败， errorCode=%s, errorMsg=%s", errorCode, errorMsg));
					logger.error(String.format("推送政务微信消息失败 = %s， sendUrl = %s， response = %s", msg, sendUrl, message));
					isError = true;
				}
				if(isError) {
					errorSmsContent = String.format(errorSmsContentFormat, errorCode, errorMsg);
				}
			} else {
				logger.error(String.format("推送微信消息, 调用政务微信接口发送微信消息失败！statusCode=%d, reason = %s, " , response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase()));
				HttpEntity resEntity = response.getEntity();
				String message = EntityUtils.toString(resEntity, "utf-8");
				logger.error(String.format("推送政务微信消息失败 = %s， sendUrl = %s, message = %s, httpStatusCode = %d", msg, sendUrl, message, httpStatusCode));
				resultStatus = ZwwxMsgSyncService.RESULT_STATUS_API_ERROR;
				if(httpStatusCode != 502) {
					isError = true;
					logger.error(String.format("推送政务微信消息失败 httpStatusCode = %d", httpStatusCode));
					errorSmsContent = String.format(errorSmsContentFormat, response.getStatusLine().toString(), "网络请求异常");
				}

			}

			if(isError && !isSendError) {
//				sendSysSMSProductorService.send(errorSmsContent);
				isError = false;
				isSendError = true;
			}
			//沉睡一下，接口不能调用的太频繁，否则会返回系统繁忙
//	        Thread.sleep(300);
		} catch(Exception ex){
			logger.error(String.format("推送微信消息, 调用政务微信接口发送微信消息异常！error = %s, " , ex.getMessage()));
			resultStatus = ZwwxMsgSyncService.RESULT_STATUS_API_ERROR;
		}
		return resultStatus;
	}

	private void clearTokenInRedis(int agentid) {
		String cache = ZwwxMsgSyncService.ZWWX_SF_CACHE_TOKEN + agentid;
		cacheClient.delete(cache);
		logger.error(String.format("推送政务微信消息时本地token过期 agentId = %d", agentid));
	}

	/**
	 * 获取token
	 * @param agentid
	 * @return
	 */
	private AccessEntity getToken(int agentid){
		String cache = ZwwxMsgSyncService.ZWWX_SF_CACHE_TOKEN + agentid;
		//先从本次定时发送的范围内获取token，一次定时发送这个方法按本次发送条数循环调用本方法的，这样提高性能
		AccessEntity entity = null;
		try{
			//先从redis缓存中取
			String token = cacheClient.getString(cache);
			if(StringUtils.isNotBlank(token)) {
				entity = new AccessEntity();
				entity.setAccess_token(token);
			}

			if(entity == null) {
				//缓存中没有，就从统一API中获取
				entity = this.getRemoteAccessToken();
				if(entity != null) {
					if(entity.getExpires_in()==null){
						entity.setExpires_in(7200);
					}
					int expireTime = entity.getExpires_in();// -120 //获取token程序存储时已经少了两分钟，这里不再减少两分钟
					cacheClient.set(cache, entity.getAccess_token(), expireTime);
				}
			}
		}catch(Exception ex){
			logger.error(String.format("通过统一API获取政务微信AccessToken异常！%s", ex.getMessage()));
		}
		return entity;
	}




	/**
	 * 获取自定义的统一访问获取AccessToken的接口（注意：这里访问的非政务微信接口）
	 * @return
	 * @throws Exception
	 */
	private AccessEntity getRemoteAccessToken() throws Exception{
		AccessEntity accessEntity = null;
		RequestConfig requestConfig = RequestConfig.custom()
				.setConnectTimeout(5000)//一、连接超时：connectionTimeout-->指的是连接一个url的连接等待时间
				.setSocketTimeout(5000) //二、读取数据超时：SocketTimeout-->指的是连接上一个url，获取response的返回等待时间
				.setConnectionRequestTimeout(5000)
				.build();
		HttpClient client = HttpClients.createDefault();
		HttpPost post = new HttpPost(zwwxTokenUnApiUrl);
		List<NameValuePair> parameters = new ArrayList<NameValuePair>();
		// 创建UrlEncodedFormEntity对象
		UrlEncodedFormEntity formEntiry = new UrlEncodedFormEntity(parameters , "UTF-8");
		post.setEntity(formEntiry);
		post.setConfig(requestConfig);
		HttpResponse response = client.execute(post);
		if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
			HttpEntity resEntity = response.getEntity();
			String data = EntityUtils.toString(resEntity, "utf-8");
			accessEntity = JsonUtils.converObjectFromJson(data, AccessEntity.class);
			logger.info("通过统一API获取政务微信AccessToken成功！");
		} else {
			logger.error(String.format("通过统一API获取政务微信AccessToken失败！%s", response.getStatusLine().getReasonPhrase()));
		}

		return accessEntity;
	}



	private Integer onSendYzyMessageHandle(String msgContent, String pfMsgReceiveId) {
		int resultStatus = ZwwxMsgSyncService.RESULT_STATUS_FAIL;

		if(StringUtils.isBlank(msgContent)) {
			logger.error("使用新版粤政易消息推送接口时，获取配置信息失败：消息内容为空");
			return ZwwxMsgSyncService.RESULT_STATUS_FAIL;
		}

		ResultData<YzyConfig> yzyConfigResultData = GdsAuthUtils.initYzyPropertiesConfig(null);
		if(!yzyConfigResultData.getSuccess()) {
			logger.error("使用新版粤政易消息推送接口时，获取配置信息失败：" + yzyConfigResultData.getDesc());
			return ZwwxMsgSyncService.RESULT_STATUS_FAIL;
		}
		ResultData<YzyMsgResponseDto> yzyMsgResponseDtoResultData = GdsAuthUtils.sendYzyMsg(msgContent);

		if(yzyMsgResponseDtoResultData.getSuccess()) {
			return null;
		}
		//发送失败需要更新状态，成功不处理
		//失败重发
		boolean isRepeatSend = true;
		int yzyMsgResponseDtoResultDataState = yzyMsgResponseDtoResultData.getState();
		if(yzyMsgResponseDtoResultDataState == -1) {
			String tryCacheKey = TRY_SEND_COUNT_CACHE_KE + pfMsgReceiveId;
			Integer trySendCount = cacheClient.getInteger(tryCacheKey);
			if(trySendCount == null) {
				trySendCount = 0;
			}
			trySendCount = trySendCount.intValue() + 1;
			cacheClient.set(tryCacheKey, trySendCount);

			if(trySendCount.intValue() >= 3) {
				//尝试发送3次后，就不发送了
				logger.error(String.format("推送政务微信消息时失败，政务微信系统繁忙，已经尝试发送了%d次，丢弃不再发送了，msgReceiverId = %s",  trySendCount, pfMsgReceiveId));
				cacheClient.delete(tryCacheKey);
				return 4;
			}
		}
		if(isRepeatSend) {
			logger.error(String.format("推送政务微信消息时失败，失败信息见上面信息，更新政务微信消息发送状态为待发送，下次再发送，msgReceiverId = %s",  pfMsgReceiveId));
			return 0;
		}

		return resultStatus;
	}



}
